#include "openglpaintingarea.h"
#include <QMouseEvent>

// 关于顶点数组对象的参考资料
// https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/

extern const char* vertexShaderCode;
extern const char* fragmentShaderCode;

static GLfloat glWidgetWidth = 0;
static GLfloat glWidgetHeight = 0;

namespace Node {

struct ControlMode cMode;
struct PainterState pState;

// use a list to save all primitives
Pic * patterns; // the head of the list

Pic * tail;     // tail of patterns

Pic * tempPic;  // temporary primitive buffer

QPointF vertex_start, vertex_end;

QVector3D tempColor;
int tempRenderType;

//GLboolean modifying;
}

OpenGLPaintingArea::OpenGLPaintingArea(QWidget *parent)
{
    Q_UNUSED(parent);

    // default to disable all ops
    Node::cMode.type = 1;
    Node::cMode.init_point = QPointF(0, 0);
    Node::cMode.pick_a_pic = false;
    Node::cMode.init_point_fix = false;
    Node::cMode.scale_a_pic = false;

    // initialize pic list
    Node::patterns = new Node::Pic;
    Node::patterns->type = 0;   // a head Node
    // 链表尾部指针，初始化指向链表头
    Node::tail = Node::patterns;

    // initialize temporary pic buffer
    Node::tempPic = new Node::Pic;
    Node::tempPic->type = 0;

    // initialize painter
    Node::pState.type = 0;        // default to draw nothing
    Node::pState.color_R = 0.0f;
    Node::pState.color_G = 0.0f;
    Node::pState.color_B = 0.0f;
    Node::pState.render_type = 1; // default to draw graph line
}

OpenGLPaintingArea::~OpenGLPaintingArea()
{
    Node::Pic * toBeDel = Node::patterns;
    while (toBeDel != NULL) {
        Node::patterns = Node::patterns->next;
        delete toBeDel;
        toBeDel = Node::patterns;
    }
    if (Node::tempPic != NULL) delete Node::tempPic;
}

void OpenGLPaintingArea::installShader()
{
    initializeOpenGLFunctions();
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    const char* adapter[1];
    adapter[0] = vertexShaderCode;
    glShaderSource(vertexShaderID, 1, adapter, 0);

    adapter[0] = fragmentShaderCode;
    glShaderSource(fragmentShaderID, 1, adapter, 0);

    glCompileShader(vertexShaderID);
    glCompileShader(fragmentShaderID);

    shaderProgramID = glCreateProgram();

    glAttachShader(shaderProgramID, vertexShaderID);
    glAttachShader(shaderProgramID, fragmentShaderID);

    glLinkProgram(shaderProgramID);
    glUseProgram(shaderProgramID);

    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);
}

void OpenGLPaintingArea::initializeGL()
{
    initializeOpenGLFunctions();
    installShader();

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    // set the background color
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
}

void OpenGLPaintingArea::paintGL()
{
    initializeOpenGLFunctions();

    // 正交投影
    glViewport(0, 0, glWidgetWidth, glWidgetHeight);
    QMatrix4x4 projection;
    projection.setToIdentity();
    projection.ortho(0.0f, glWidgetWidth, 0.0f, glWidgetHeight, -1.0f, 1.0f);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgramID, "projection"), 1, GL_FALSE, projection.data());

    // 绘制链表结构中存储的图元
    Node::Pic *toBePaint = Node::patterns->next;
    while (toBePaint != NULL) {
        toBePaint->draw(shaderProgramID);
        //下一个图元
        toBePaint = toBePaint->next;
    }

    if (Node::tempPic->type != 0) {
        Node::tempPic->midPicDraw(shaderProgramID);
    }
}

void OpenGLPaintingArea::resizeGL(int w, int h)
{
    glWidgetWidth = width();
    glWidgetHeight = height();
    Q_UNUSED(w);
    Q_UNUSED(h);
}

void OpenGLPaintingArea::mousePressEvent(QMouseEvent *event)
{ //qDebug() << "press";
    QPointF t;
    t.setX(event->pos().x());
    t.setY(glWidgetHeight - event->pos().y());

    // check control-mode; 1: painting
    if (Node::cMode.type == 1) {
        Node::tempPic->rgb[0] = Node::pState.color_R;
        Node::tempPic->rgb[1] = Node::pState.color_G;
        Node::tempPic->rgb[2] = Node::pState.color_B;
        switch (Node::pState.type) {
        case 0:
            qDebug() << "Please choose a type of graph!";
            break;
        case 1: // 等腰三角形
            Node::tempPic->verts = new GLfloat[9];
            Node::tempPic->v_size = 9 * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[3];
            Node::tempPic->i_size = 3 * sizeof(GLushort);
            Node::tempPic->verts[1] = t.y();
            Node::tempPic->verts[6] = t.x();
            // avoid one click
            Node::tempPic->verts[0] = t.x();
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[4] = t.y();
            Node::tempPic->verts[7] = t.y();
            for (int i = 0; i < 3; ++i) {
                Node::tempPic->verts[2 + 3*i] = 0.0f;
            }
            Node::tempPic->indices[0] = 0;
            Node::tempPic->indices[1] = 1;
            Node::tempPic->indices[2] = 2;
            break;
        case 2: // 矩形
            Node::tempPic->verts = new GLfloat[12];
            Node::tempPic->v_size = 12 * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[4];
            Node::tempPic->i_size = 4 * sizeof(GLushort);
            Node::tempPic->verts[0] = t.x();
            Node::tempPic->verts[1] = t.y();
            Node::tempPic->verts[4] = t.y();
            Node::tempPic->verts[9] = t.x();
            // avoid one click
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[6] = t.x();
            Node::tempPic->verts[7] = t.y();
            Node::tempPic->verts[10] = t.y();
            for (int i = 0; i < 4; ++i) {
                Node::tempPic->verts[2 + 3*i] = 0.0f;
            }
            Node::tempPic->indices[0] = 0;
            Node::tempPic->indices[1] = 1;
            Node::tempPic->indices[2] = 2;
            Node::tempPic->indices[3] = 3;
            break;
        case 3: // 直线
            Node::tempPic->verts = new GLfloat[6];
            Node::tempPic->v_size = 6 * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[2];
            Node::tempPic->i_size = 2 * sizeof(GLushort);
            Node::tempPic->verts[0] = t.x();
            Node::tempPic->verts[1] = t.y();
            // avoid one click
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[4] = t.y();
            Node::tempPic->verts[2] = Node::tempPic->verts[5] = 0.0f;
            Node::tempPic->indices[0] = 0;
            Node::tempPic->indices[1] = 1;
            break;
        case 4: // 圆角矩形
            Node::tempPic->verts = new GLfloat[3 * (4*CIRCLE_POINTS_NUM)];
            Node::tempPic->v_size = 3 * (4*CIRCLE_POINTS_NUM) * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[(4*CIRCLE_POINTS_NUM)];
            Node::tempPic->i_size = (4*CIRCLE_POINTS_NUM) * sizeof(GLushort);
            Node::vertex_start = t;
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0) t1 = -t1;
                    if (t2 < 0) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 5;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR;
                }
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->verts[2 + 3*i] = 0.0f;
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->indices[i] = i;
            }
            break;
        case 5: // 圆
            Node::tempPic->verts = new GLfloat[3 * (4*CIRCLE_POINTS_NUM)];
            Node::tempPic->v_size = 3 * (4*CIRCLE_POINTS_NUM) * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[(4*CIRCLE_POINTS_NUM)];
            Node::tempPic->i_size = (4*CIRCLE_POINTS_NUM) * sizeof(GLushort);
            Node::vertex_start = t;
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0) t1 = -t1;
                    if (t2 < 0) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 2;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR;
                }
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->verts[2 + 3*i] = 0.0f;
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->indices[i] = i;
            }
            break;
        case 6: // 椭圆
            Node::tempPic->verts = new GLfloat[3 * (4*CIRCLE_POINTS_NUM)];
            Node::tempPic->v_size = 3 * (4*CIRCLE_POINTS_NUM) * sizeof(GLfloat);
            Node::tempPic->indices = new GLushort[(4*CIRCLE_POINTS_NUM)];
            Node::tempPic->i_size = (4*CIRCLE_POINTS_NUM) * sizeof(GLushort);
            Node::vertex_start = t;
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0) t1 = -t1;
                    if (t2 < 0) t2 = -t2;
                    t1 /= 2;
                    t2 /= 2;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t2;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t1;
                }
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->verts[2 + 3*i] = 0.0f;
            }
            for (int i = 0; i < 4*CIRCLE_POINTS_NUM; ++i) {
                Node::tempPic->indices[i] = i;
            }
            break;
        case 7: // 多边形
            Node::tempPic->type = 7;
            if (Node::tempPic->verts == NULL) {
                Node::tempPic->verts = new GLfloat[3];
                Node::tempPic->v_size = 3 * sizeof(GLfloat);
                Node::tempPic->indices = new GLushort[1];
                Node::tempPic->i_size = 1 * sizeof(GLushort);
                Node::tempPic->verts[0] = t.x();
                Node::tempPic->verts[1] = t.y();
                Node::tempPic->verts[2] = 0.0f;
                Node::tempPic->indices[0] = 0;
            } else {
                GLfloat * vp = Node::tempPic->verts;
                GLushort *ip = Node::tempPic->indices;
                Node::tempPic->verts = new GLfloat[Node::tempPic->v_size/sizeof(GLfloat) + 3];
                Node::tempPic->v_size = (Node::tempPic->v_size/sizeof(GLfloat) + 3) * sizeof(GLfloat);
                Node::tempPic->indices = new GLushort[Node::tempPic->i_size/sizeof(GLushort) + 1];
                Node::tempPic->i_size = (Node::tempPic->i_size/sizeof(GLushort) + 1) * sizeof(GLushort);
                for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat) - 3; ++i)
                    Node::tempPic->verts[i] = vp[i];
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 3] = t.x();
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 2] = t.y();
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 1] = 0.0f;
                for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
                    Node::tempPic->indices[i] = i;
                delete vp;
                delete ip;
            }
            break;
        case 8: // 曲线
            Node::tempPic->type = 8;
            if (Node::tempPic->verts == NULL) {
                Node::tempPic->verts = new GLfloat[3];
                Node::tempPic->v_size = 3 * sizeof(GLfloat);
                Node::tempPic->indices = new GLushort[1];
                Node::tempPic->i_size = 1 * sizeof(GLushort);
                Node::tempPic->verts[0] = t.x();
                Node::tempPic->verts[1] = t.y();
                Node::tempPic->verts[2] = 0.0f;
                Node::tempPic->indices[0] = 0;
            } else {
                GLfloat * vp = Node::tempPic->verts;
                GLushort *ip = Node::tempPic->indices;
                Node::tempPic->verts = new GLfloat[Node::tempPic->v_size/sizeof(GLfloat) + 3];
                Node::tempPic->v_size = (Node::tempPic->v_size/sizeof(GLfloat) + 3) * sizeof(GLfloat);
                Node::tempPic->indices = new GLushort[Node::tempPic->i_size/sizeof(GLushort) + 1];
                Node::tempPic->i_size = (Node::tempPic->i_size/sizeof(GLushort) + 1) * sizeof(GLushort);
                for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat) - 3; ++i)
                    Node::tempPic->verts[i] = vp[i];
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 3] = t.x();
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 2] = t.y();
                Node::tempPic->verts[Node::tempPic->v_size/sizeof(GLfloat) - 1] = 0.0f;
                for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
                    Node::tempPic->indices[i] = i;
                delete vp;
                delete ip;
            }
            break;
        default:
            break;
        }
        update();
    }

    // check control-mode; 3: drag
    if (Node::cMode.type == 3 && Node::cMode.pick_a_pic == true) {
        // in second step of drag
        Node::cMode.init_point = t;
        Node::cMode.init_point_fix = true;
        return ;
    }
}

void OpenGLPaintingArea::mouseMoveEvent(QMouseEvent *event)
{ //qDebug() << "move";
    QPointF t;
    t.setX(event->pos().x());
    t.setY(glWidgetHeight - event->pos().y());

    // for location
    GLfloat centralX = Node::vertex_start.x() + (Node::vertex_end.x() - Node::vertex_start.x())/2;
    GLfloat centralY = Node::vertex_start.y() + (Node::vertex_end.y() - Node::vertex_start.y())/2;

    // for circle left&up align
    GLfloat lenX = Node::vertex_end.x() - Node::vertex_start.x();
    GLfloat lenY = Node::vertex_end.y() - Node::vertex_start.y();
    GLfloat len = lenX * lenX < lenY * lenY ? lenX : lenY;
    if (len < 0) len = -len;
    GLfloat newCentralX = Node::vertex_start.x() + ((Node::vertex_end.x() - Node::vertex_start.x()) < 0 ? -len : len)/2;
    GLfloat newCentralY = Node::vertex_start.y() + ((Node::vertex_end.y() - Node::vertex_start.y()) < 0 ? -len : len)/2;

    // check control-mode; 1: painting
    if (Node::cMode.type == 1 && Node::tempPic->verts != NULL) {
        Node::tempPic->render_type = Node::pState.render_type;
        switch (Node::pState.type) {
        case 0:
            // do nothing
            break;
        case 1: // 等腰三角形
            Node::tempPic->verts[0] = (Node::tempPic->verts[6] + t.x()) / 2;
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[4] = t.y();
            Node::tempPic->verts[7] = t.y();
            Node::tempPic->type = 1;
            break;
        case 2: // 矩形
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[10] = t.y();
            Node::tempPic->verts[6] = t.x();
            Node::tempPic->verts[7] = t.y();
            Node::tempPic->type = 2;
            break;
        case 3: // 直线
            Node::tempPic->verts[3] = t.x();
            Node::tempPic->verts[4] = t.y();
            Node::tempPic->type = 3;
            break;
        case 4: // 圆角矩形
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 5; t1 -= 2*tR; t2 -= 2*tR;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + centralX;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + centralY;
                    if (i == 0 || i == 3)
                        Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] += t2/2;
                    if (i == 1 || i == 2)
                        Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] -= t2/2;
                    if (i == 0 || i == 1)
                        Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] += t1/2;
                    if (i == 2 || i == 3)
                        Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] -= t1/2;
                }
            }
            Node::tempPic->type = 4;
            break;
        case 5: // 圆
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 2;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + newCentralX;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + newCentralY;
                }
            }
            Node::tempPic->type = 5;
            break;
        case 6: // 椭圆
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    t1 /= 2;
                    t2 /= 2;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t2 + centralX;
                    Node::tempPic->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t1 + centralY;
                }
            }
            Node::tempPic->type = 6;
            break;
        default:
            break;
        }
    }

    // check control-mode; 3: drag
    if (Node::cMode.type == 3 && Node::cMode.pick_a_pic == true && Node::cMode.init_point_fix == true) {
        // in second step of drag
        GLfloat x_mov = t.x() - Node::cMode.init_point.x();
        GLfloat y_mov = t.y() - Node::cMode.init_point.y();

        if (Node::tempPic->check_point(t)) {
            setCursor(Qt::SizeAllCursor);
            Node::tempPic->move(x_mov, y_mov);
            Node::cMode.init_point = t;
        } else
            setCursor(Qt::CrossCursor);
    }

    update();
}

void OpenGLPaintingArea::mouseReleaseEvent(QMouseEvent *event)
{ //qDebug() << "release";
    QPointF t;
    t.setX(event->pos().x());
    t.setY(glWidgetHeight - event->pos().y());

    // for location
    GLfloat centralX = Node::vertex_start.x() + (Node::vertex_end.x() - Node::vertex_start.x())/2;
    GLfloat centralY = Node::vertex_start.y() + (Node::vertex_end.y() - Node::vertex_start.y())/2;

    // for circle left&up align
    GLfloat lenX = Node::vertex_end.x() - Node::vertex_start.x();
    GLfloat lenY = Node::vertex_end.y() - Node::vertex_start.y();
    GLfloat len = lenX * lenX < lenY * lenY ? lenX : lenY;
    if (len < 0) len = -len;
    GLfloat newCentralX = Node::vertex_start.x() + ((Node::vertex_end.x() - Node::vertex_start.x()) < 0 ? -len : len)/2;
    GLfloat newCentralY = Node::vertex_start.y() + ((Node::vertex_end.y() - Node::vertex_start.y()) < 0 ? -len : len)/2;

    // check control-mode; 1: painting
    if (Node::cMode.type == 1 && Node::tempPic->verts != NULL) {
        // just do nothing
        if (Node::pState.type == 7 || Node::pState.type == 8) return ;

        while (Node::tail->next != NULL) {
            Node::tail = Node::tail->next;
        }
        Node::Pic * p = Node::tail;
        p->next = new Node::Pic(*Node::tempPic);
        p->next->prev = p; // doubly-link list
        p = p->next;
        p->next = NULL;
//        p->type = Node::tempPic->type;
//        p->render_type = Node::tempPic->render_type;
//        p->v_size = Node::tempPic->v_size;
//        p->i_size = Node::tempPic->i_size;
//        p->verts = new GLfloat[p->v_size/sizeof(GLfloat)];
//        for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat); ++i)
//            p->verts[i] = Node::tempPic->verts[i];
//        p->indices = new GLushort[p->i_size/sizeof(GLushort)];
//        for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
//            p->indices[i] = Node::tempPic->indices[i];
//        p->hasVAO = false;
//        p->rgb[0] = Node::tempPic->rgb[0];
//        p->rgb[1] = Node::tempPic->rgb[1];
//        p->rgb[2] = Node::tempPic->rgb[2];

        switch (p->type) {
        case 0:
            // do nothing
            break;
        case 1: // 等腰三角形
            p->verts[0] = (p->verts[6] + t.x()) / 2;
            p->verts[3] = t.x();
            p->verts[4] = t.y();
            p->verts[7] = t.y();
            break;
        case 2: // 矩形
            p->verts[3] = t.x();
            p->verts[10] = t.y();
            p->verts[6] = t.x();
            p->verts[7] = t.y();
            break;
        case 3: // 直线
            p->verts[3] = t.x();
            p->verts[4] = t.y();
            break;
        case 4: // 圆角矩形
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 5; t1 -= 2*tR; t2 -= 2*tR;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + centralX;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + centralY;
                    if (i == 0 || i == 3)
                        p->verts[(i*CIRCLE_POINTS_NUM + j) * 3] += t2/2;
                    if (i == 1 || i == 2)
                        p->verts[(i*CIRCLE_POINTS_NUM + j) * 3] -= t2/2;
                    if (i == 0 || i == 1)
                        p->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] += t1/2;
                    if (i == 2 || i == 3)
                        p->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] -= t1/2;
                }
            }
            break;
        case 5: // 圆
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    GLfloat tR = t1 < t2 ? t1 : t2;
                    tR /= 2;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + newCentralX;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * tR + newCentralY;
                }
            }
            break;
        case 6: // 椭圆
            Node::vertex_end = t;
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < CIRCLE_POINTS_NUM; ++j) {
                    GLfloat t1 = Node::vertex_end.y() - Node::vertex_start.y();
                    GLfloat t2 = Node::vertex_end.x() - Node::vertex_start.x();
                    if (t1 < 0.0F) t1 = -t1;
                    if (t2 < 0.0F) t2 = -t2;
                    t1 /= 2;
                    t2 /= 2;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3] =
                            cos(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t2 + centralX;
                    p->verts[(i*CIRCLE_POINTS_NUM + j) * 3 + 1] =
                            sin(qDegreesToRadians(i * 90.0f + (j + 1) * 90.0f/CIRCLE_POINTS_NUM)) * t1 + centralY;
                }
            }
            break;
        default:
            break;
        }
        Node::tempPic->type = 0;
        Node::tempPic->next = NULL;
        Node::tempPic->prev = NULL;
        delete Node::tempPic->verts;
        delete Node::tempPic->indices;
        Node::tempPic->verts = NULL;
        Node::tempPic->indices = NULL;
    }

    // check control-mode; 3: drag
    if (Node::cMode.type == 3 && Node::cMode.pick_a_pic == true && Node::cMode.init_point_fix == true) {
        // return in first step of drag
        Node::cMode.init_point_fix = false;
        return ;
    }

    update();
}

void OpenGLPaintingArea::mouseDoubleClickEvent(QMouseEvent *event)
{   //qDebug() << "dclick";
    QPointF t;
    t.setX(event->pos().x());
    t.setY(glWidgetHeight - event->pos().y());

    // check control-mode; 3: drag
    if (Node::cMode.type == 3  && Node::cMode.pick_a_pic == false) {

        while (Node::tail->next != NULL) {
            Node::tail = Node::tail->next;
        }

        Node::Pic * p = Node::tail;
        while (p != NULL && Node::cMode.pick_a_pic == false) {
            // 从尾到头找
            Node::cMode.pick_a_pic = p->check_point(t);
            if (Node::cMode.pick_a_pic == false)
                p = p->prev;
        }
        if (Node::cMode.pick_a_pic == false) {
            return ;
        }

        // 被选中的图元填充颜色变为背景色，虚线
        // 修改链表，剥离p
        Node::Pic * p_next = p->next;
        if (p_next != NULL) {
            p_next->prev = p->prev;
        } else {
            // 此时tail 与 p 重叠，后面销毁p会使tail失效
            Node::tail = Node::patterns;
        }
        p->prev->next = p_next;
        // 复制该顶点到Node::tempPic
        Node::tempPic->next = NULL;
        Node::tempPic->prev = NULL;
        Node::tempPic->type = p->type;
        Node::tempPic->render_type = p->render_type;
        Node::tempPic->v_size = p->v_size;
        Node::tempPic->i_size = p->i_size;
        Node::tempPic->verts = new GLfloat[Node::tempPic->v_size/sizeof(GLfloat)];
        for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat); ++i)
            Node::tempPic->verts[i] = p->verts[i];
        Node::tempPic->indices = new GLushort[Node::tempPic->i_size/sizeof(GLushort)];
        for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
            Node::tempPic->indices[i] = p->indices[i];
        Node::tempPic->hasVAO = false;
        Node::tempPic->rgb[0] = p->rgb[0];
        Node::tempPic->rgb[1] = p->rgb[1];
        Node::tempPic->rgb[2] = p->rgb[2];
        // 删除该结点
        delete p;
        p = NULL;
        Node::tempColor.setX(Node::tempPic->rgb[0]);
        Node::tempColor.setY(Node::tempPic->rgb[1]);
        Node::tempColor.setZ(Node::tempPic->rgb[2]);
        Node::tempRenderType = Node::tempPic->render_type;
        // 修改顶点rgb 1, 0.117647, 0.235294
        Node::tempPic->rgb[0] = 1.0;
        Node::tempPic->rgb[1] = 0.1176;
        Node::tempPic->rgb[2] = 0.2352;
        update();

        // second step of drag
        Node::cMode.pick_a_pic = true;

        // 追踪鼠标
        setMouseTracking(true);
    }

    if ((Node::cMode.type == 2 || Node::cMode.type == 4 || Node::cMode.type == 5) && Node::cMode.scale_a_pic == false) {

        while (Node::tail->next != NULL) {
            Node::tail = Node::tail->next;
        }

        Node::Pic * p = Node::tail;
        while (p != NULL && Node::cMode.scale_a_pic == false) {
            // 从尾到头找
            Node::cMode.scale_a_pic = p->check_point(t);
            if (Node::cMode.scale_a_pic == false)
                p = p->prev;
        }
        if (Node::cMode.scale_a_pic == false) {
            return ;
        }

        // 被选中的图元填充颜色变为背景色，虚线
        // 修改链表，剥离p
        Node::Pic * p_next = p->next;
        if (p_next != NULL) {
            p_next->prev = p->prev;
        } else {
            // 此时tail 与 p 重叠，后面销毁p会使tail失效
            Node::tail = Node::patterns;
        }
        p->prev->next = p_next;
        // 复制该顶点到Node::tempPic
        Node::tempPic->next = NULL;
        Node::tempPic->prev = NULL;
        Node::tempPic->type = p->type;
        Node::tempPic->render_type = p->render_type;
        Node::tempPic->v_size = p->v_size;
        Node::tempPic->i_size = p->i_size;
        Node::tempPic->verts = new GLfloat[Node::tempPic->v_size/sizeof(GLfloat)];
        for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat); ++i)
            Node::tempPic->verts[i] = p->verts[i];
        Node::tempPic->indices = new GLushort[Node::tempPic->i_size/sizeof(GLushort)];
        for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
            Node::tempPic->indices[i] = p->indices[i];
        Node::tempPic->hasVAO = false;
        Node::tempPic->rgb[0] = p->rgb[0];
        Node::tempPic->rgb[1] = p->rgb[1];
        Node::tempPic->rgb[2] = p->rgb[2];
        // 删除该结点
        delete p;
        p = NULL;
        Node::tempColor.setX(Node::tempPic->rgb[0]);
        Node::tempColor.setY(Node::tempPic->rgb[1]);
        Node::tempColor.setZ(Node::tempPic->rgb[2]);
        Node::tempRenderType = Node::tempPic->render_type;
        // 修改顶点rgb 1, 0.117647, 0.235294
        Node::tempPic->rgb[0] = 1.0;
        Node::tempPic->rgb[1] = 0.1176;
        Node::tempPic->rgb[2] = 0.2352;
        update();

        // second step of drag
        Node::cMode.scale_a_pic = true;

        // 改变鼠标形状
        setCursor(Qt::OpenHandCursor);
    }

}

void OpenGLPaintingArea::wheelEvent(QWheelEvent *event)
{   //qDebug() << "whl";
    float x_scale = 1.0f, y_scale = 1.0f;
    if (event->delta() > 0) {
        x_scale = 1.0/0.9;
        y_scale = 1.0/0.9;
    } else {
        x_scale = 0.9;
        y_scale = 0.9;
    }
    // check control-mode; 2: scale
    if (Node::cMode.type == 2 && Node::cMode.scale_a_pic == true) {
        Node::tempPic->scale(x_scale, y_scale);
    }
    // check control-mode; 4: X-scale
    if (Node::cMode.type == 4 && Node::cMode.scale_a_pic == true) {
        Node::tempPic->scale(x_scale, 1.0f);
    }
    // check control-mode; 5: Y-scale
    if (Node::cMode.type == 5 && Node::cMode.scale_a_pic == true) {
        Node::tempPic->scale(1.0f, y_scale);
    }
    update();
}

void OpenGLPaintingArea::keyPressEvent(QKeyEvent *event)
{   //qDebug() << "key";
    // check control-mode; 3: drag
    if ((Node::cMode.type == 3 || Node::cMode.type == 2 || Node::cMode.type == 4 || Node::cMode.type == 5) && (Node::cMode.pick_a_pic == true || Node::cMode.scale_a_pic == true)) {
        // 取消追踪鼠标
        setMouseTracking(false);
        setCursor(Qt::CrossCursor);

        if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return){
            // 确认：重绘图形用新的颜色与模式
            while (Node::tail->next != NULL) {
                Node::tail = Node::tail->next;
            }
            Node::Pic * p = Node::tail;
            p->next = new Node::Pic(*Node::tempPic);
            p->next->prev = p; // doubly-link list
            p = p->next;
            p->next = NULL;
//            p->type = Node::tempPic->type;
//            p->render_type = Node::pState.render_type;
//            p->v_size = Node::tempPic->v_size;
//            p->i_size = Node::tempPic->i_size;
//            p->verts = new GLfloat[p->v_size/sizeof(GLfloat)];
//            for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat); ++i) {
//                p->verts[i] = Node::tempPic->verts[i];
//            }
//            p->indices = new GLushort[p->i_size/sizeof(GLushort)];
//            for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
//                p->indices[i] = Node::tempPic->indices[i];
//            p->hasVAO = false;
            p->render_type = Node::pState.render_type;
            p->rgb[0] = Node::pState.color_R;
            p->rgb[1] = Node::pState.color_G;
            p->rgb[2] = Node::pState.color_B;
            Node::tempPic->type = 0;
            Node::tempPic->next = NULL;
            Node::tempPic->prev = NULL;
            //Node::tempPic->hasVAO = false;
            delete Node::tempPic->verts;
            delete Node::tempPic->indices;
            Node::tempPic->verts = NULL;
            Node::tempPic->indices = NULL;

            Node::cMode.pick_a_pic = false;
            Node::cMode.scale_a_pic = false;
        } else if (event->key() == Qt::Key_Backspace) { // 确认：用原颜色与模式重绘
            while (Node::tail->next != NULL) {
                Node::tail = Node::tail->next;
            }
            Node::Pic * p = Node::tail;
            p->next = new Node::Pic(*Node::tempPic);
            p->next->prev = p; // doubly-link list
            p = p->next;
            p->next = NULL;
//            p->type = Node::tempPic->type;
//            p->render_type = Node::tempRenderType;
//            p->v_size = Node::tempPic->v_size;
//            p->i_size = Node::tempPic->i_size;
//            p->verts = new GLfloat[p->v_size/sizeof(GLfloat)];
//            for (unsigned int i = 0; i < Node::tempPic->v_size/sizeof(GLfloat); ++i) {
//                p->verts[i] = Node::tempPic->verts[i];
//            }
//            p->indices = new GLushort[p->i_size/sizeof(GLushort)];
//            for (unsigned int i = 0; i < Node::tempPic->i_size/sizeof(GLushort); ++i)
//                p->indices[i] = Node::tempPic->indices[i];
//            p->hasVAO = false;
            p->render_type = Node::tempRenderType;
            p->rgb[0] = Node::tempColor.x();
            p->rgb[1] = Node::tempColor.y();
            p->rgb[2] = Node::tempColor.z();
            Node::tempPic->type = 0;
            Node::tempPic->next = NULL;
            Node::tempPic->prev = NULL;
            //Node::tempPic->hasVAO = false;
            delete Node::tempPic->verts;
            delete Node::tempPic->indices;
            Node::tempPic->verts = NULL;
            Node::tempPic->indices = NULL;

            Node::cMode.pick_a_pic = false;
            Node::cMode.scale_a_pic = false;
        } else if (event->key() == Qt::Key_Delete) { // 确认：删除图形
            //Node::tempPic->hasVAO = false;
            delete Node::tempPic->verts;
            delete Node::tempPic->indices;
            Node::tempPic->verts = NULL;
            Node::tempPic->indices = NULL;
            Node::tempPic->type = 0;
            Node::tempPic->next = NULL;
            Node::tempPic->prev = NULL;

            Node::cMode.pick_a_pic = false;
            Node::cMode.scale_a_pic = false;
        }
        update();
    }

    // paint a polygon or curve
    if ((Node::cMode.type == 1 && Node::pState.type == 7) || (Node::cMode.type == 1 && Node::pState.type == 8)) {
        if (event->key() == Qt::Key_Enter  || event->key() == Qt::Key_Return) {
            // 确认绘制多边形图形
            while (Node::tail->next != NULL) {
                Node::tail = Node::tail->next;
            }
            Node::Pic * p = Node::tail;
            p->next = new Node::Pic(*Node::tempPic);
            p->next->prev = p; // doubly-link list
            p = p->next;
            p->next = NULL;

            p->render_type = Node::pState.render_type;
            p->rgb[0] = Node::pState.color_R;
            p->rgb[1] = Node::pState.color_G;
            p->rgb[2] = Node::pState.color_B;
            Node::tempPic->type = 0;
            Node::tempPic->next = NULL;
            Node::tempPic->prev = NULL;
            delete Node::tempPic->verts;
            delete Node::tempPic->indices;
            Node::tempPic->verts = NULL;
            Node::tempPic->indices = NULL;
        } else if (event->key() == Qt::Key_Delete) {
            // 确认删除多边形图形
            delete Node::tempPic->verts;
            delete Node::tempPic->indices;
            Node::tempPic->verts = NULL;
            Node::tempPic->indices = NULL;
            Node::tempPic->type = 0;
            Node::tempPic->next = NULL;
            Node::tempPic->prev = NULL;
        }
        update();
    }

}
